package order

import (
	"context"
	"strings"
	"time"

	"mall/common/globalkey"
	"mall/common/moneyx"
	"mall/common/mqueuex"
	"mall/common/resultx"
	"mall/service/backend/common/i18n"
	"mall/service/order/model"
	"mall/service/order/rpc/internal/svc"
	"mall/service/order/rpc/types/order"

	"github.com/volatiletech/null/v8"
	"github.com/zeromicro/go-zero/core/logx"
)

type UpdateOrderLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewUpdateOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *UpdateOrderLogic {
	return &UpdateOrderLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *UpdateOrderLogic) UpdateOrder(in *order.OrderInfo) (*order.BaseResp, error) {
	if in.Id == nil || in.UserId == nil || *in.Id == 0 || *in.UserId == 0 {
		return nil, resultx.StatusError(resultx.ORDER_PARAM_INVALID, "")
	}

	trade, err := l.svcCtx.Order.FindOneNoCache(l.ctx, nil, *in.Id)
	if err != nil {
		if err == model.ErrNotFound {
			return nil, resultx.StatusError(resultx.ORDER_ID_INVALID, "")
		}

		return nil, err
	}

	if trade.UserID != *in.UserId {
		return nil, resultx.StatusError(resultx.ORDER_ID_INVALID, "")
	}

	if in.TradeState != nil && *in.TradeState > 0 {
		trade.TradeState = uint16(*in.TradeState)
	}

	now := time.Now()
	trade.UpdatedAt = now

	rel := &model.OrderRel{}

	if in.Remark != nil && len(strings.TrimSpace(*in.Remark)) > 0 {
		var opType uint8 = 11
		opName := "用户修改备注"
		opCode := "user edit remark"
		memo := "原备注:" + trade.Remark
		rel.Logs = append(rel.Logs, &model.OrderOperateLog{
			TradeState: trade.TradeState,
			Type:       opType,
			Name:       opName,
			Code:       opCode,
			Status:     uint8(globalkey.StatusEnabled),
			Memo:       memo,
			OperatedBy: *in.UserId,
			OperatedAt: null.TimeFrom(now),
		})

		trade.Remark = strings.TrimSpace(*in.Remark)
	}

	if in.NewAddress != nil {
		newAddress := in.NewAddress
		if newAddress.UserId != nil && *newAddress.UserId == *in.UserId {
			address := &model.OrderAddress{
				UserID: *newAddress.UserId,
				Status: uint8(globalkey.StatusEnabled),
			}

			if newAddress.Consignee != nil && len(strings.TrimSpace(*newAddress.Consignee)) > 0 {
				address.Consignee = strings.TrimSpace(*newAddress.Consignee)
			}
			if newAddress.Mobile != nil && len(strings.TrimSpace(*newAddress.Mobile)) > 0 {
				address.Mobile = strings.TrimSpace(*newAddress.Mobile)
			}
			if newAddress.Province != nil && len(strings.TrimSpace(*newAddress.Province)) > 0 {
				address.Province = strings.TrimSpace(*newAddress.Province)
			}
			if newAddress.City != nil && len(strings.TrimSpace(*newAddress.City)) > 0 {
				address.City = strings.TrimSpace(*newAddress.City)
			}
			if newAddress.District != nil && len(strings.TrimSpace(*newAddress.District)) > 0 {
				address.District = strings.TrimSpace(*newAddress.District)
			}
			if newAddress.Street != nil && len(strings.TrimSpace(*newAddress.Street)) > 0 {
				address.Street = strings.TrimSpace(*newAddress.Street)
			}
			if newAddress.Address != nil && len(strings.TrimSpace(*newAddress.Address)) > 0 {
				address.DetailedAddress = strings.TrimSpace(*newAddress.Address)
			}
			if newAddress.PostalCode != nil && len(strings.TrimSpace(*newAddress.PostalCode)) > 0 {
				address.PostalCode = strings.TrimSpace(*newAddress.PostalCode)
			}
			if newAddress.RegionCode != nil && len(strings.TrimSpace(*newAddress.RegionCode)) > 0 {
				address.RegionCode = strings.TrimSpace(*newAddress.RegionCode)
			}

			rel.Addresses = append(rel.Addresses, address)
		}
	}

	if in.NewPayment != nil {
		newPayment := in.NewPayment

		var payment *model.OrderPayment

		if newPayment.Id != nil && *newPayment.Id > 0 {
			filterMap := make(map[string]map[string][]any)
			filterMap[model.OrderPaymentColumns.OrderPaymentID] = map[string][]any{
				"equalTo": []any{*newPayment.Id},
			}
			list, _, err := l.svcCtx.Order.GetPaymentList(l.ctx, model.M{
				"pageSize": uint64(1),
			}, -1, filterMap)
			if err != nil {
				return nil, err
			}

			if len(list) == 0 {
				return nil, resultx.StatusError(resultx.ORDER_PARAM_INVALID, "")
			}

			payment = list[0]
		} else if newPayment.Amount != nil && len(strings.TrimSpace(*newPayment.Amount)) > 0 {
			if amount, err := moneyx.ParseAmount(strings.TrimSpace(*newPayment.Amount)); err != nil {
				logx.Errorw("UpdateOrder failed to ParseAmount", logx.Field("detail", err.Error()))
				return nil, resultx.StatusError(resultx.ORDER_PARAM_INVALID, "")
			} else {
				payment = &model.OrderPayment{
					Amount: uint64(amount),
				}
			}
		}

		if newPayment.No != nil && len(strings.TrimSpace(*newPayment.No)) > 0 {
			payment.No = strings.TrimSpace(*newPayment.No)
		}
		if newPayment.Type != nil && *newPayment.Type > 0 {
			payment.Type = uint8(*newPayment.Type)
		}
		if newPayment.Name != nil && len(strings.TrimSpace(*newPayment.Name)) > 0 {
			payment.Name = strings.TrimSpace(*newPayment.Name)
		}
		if newPayment.Code != nil && len(strings.TrimSpace(*newPayment.Code)) > 0 {
			payment.Code = strings.TrimSpace(*newPayment.Code)
		}
		if newPayment.Status != nil && *newPayment.Status > 0 {
			payment.Status = uint8(*newPayment.Status)
		} else {
			payment.Status = uint8(mqueuex.PaymentStatusNotPay)
		}
		if newPayment.PaidAt != nil {
			payment.PaidAt = null.TimeFrom(now)
		} else if newPayment.Id == nil {
			payment.PaidAt = null.TimeFromPtr(nil)
		}

		rel.Payments = append(rel.Payments, payment)
	}

	if in.NewShipment != nil {
		newShipment := in.NewShipment

		shipment := &model.OrderShipment{
			Status: uint8(globalkey.StatusEnabled),
		}

		if newShipment.No != nil && len(strings.TrimSpace(*newShipment.No)) > 0 {
			shipment.No = strings.TrimSpace(*newShipment.No)
		}
		if newShipment.Type != nil && *newShipment.Type > 0 {
			shipment.Type = uint8(*newShipment.Type)
		}
		if newShipment.Name != nil && len(strings.TrimSpace(*newShipment.Name)) > 0 {
			shipment.Name = strings.TrimSpace(*newShipment.Name)
		}
		if newShipment.Code != nil && len(strings.TrimSpace(*newShipment.Code)) > 0 {
			shipment.Code = strings.TrimSpace(*newShipment.Code)
		}

		rel.Shipments = append(rel.Shipments, shipment)
	}

	if in.NewRefund != nil {
		newRefund := in.NewRefund

		if newRefund.Amount != nil && len(strings.TrimSpace(*newRefund.Amount)) > 0 {
			if amount, err := moneyx.ParseAmount(strings.TrimSpace(*newRefund.Amount)); err != nil {
				logx.Errorw("UpdateOrder failed to ParseAmount", logx.Field("detail", err.Error()))
				return nil, resultx.StatusError(resultx.ORDER_PARAM_INVALID, "")
			} else {
				refund := &model.OrderRefund{
					Amount: uint64(amount),
				}

				if newRefund.PaymentId != nil && *newRefund.PaymentId > 0 {
					refund.OrderPaymentID = *newRefund.PaymentId
				}
				if newRefund.RefundNo != nil && len(strings.TrimSpace(*newRefund.RefundNo)) > 0 {
					refund.RefundNo = strings.TrimSpace(*newRefund.RefundNo)
				}
				if newRefund.RefundId != nil && len(strings.TrimSpace(*newRefund.RefundId)) > 0 {
					refund.RefundID = strings.TrimSpace(*newRefund.RefundId)
				}
				if newRefund.Status != nil && *newRefund.Status > 0 {
					refund.Status = uint8(*newRefund.Status)
				} else {
					refund.Status = uint8(mqueuex.PaymentStatusNotPay)
				}
				if newRefund.RefundAt != nil {
					refund.RefundAt = null.TimeFrom(now)
				} else {
					refund.RefundAt = null.TimeFromPtr(nil)
				}

				rel.Refunds = append(rel.Refunds, refund)
			}
		}
	}

	err = l.svcCtx.Order.Update(l.ctx, nil, trade, rel)
	if err != nil {
		return nil, err
	}

	return &order.BaseResp{
		Msg: i18n.UpdateSuccess,
	}, nil
}
